PROJECT = "ModbusRTU库主站测试"
VERSION = "1.0.0"

-- 测试Modbus主站库，使用串口11
local sys = require("sys")
local ModbusRTU_Master = require("ModbusRTU_Master") -- 引入ModbusRTU主站库


if wdt then
    -- 添加硬狗防止程序卡死，在支持的设备上启用这个功能
    wdt.init(9000)--初始化watchdog设置为9s
    sys.timerLoopStart(wdt.feed, 3000)--3s喂一次狗
end
 
-- 创建ModbusRTU主站实例  依次是 串口号   波特率  数据位  停止位  校验位
local uart11 = ModbusRTU_Master:new({uartid = 11, baudrate = 9600, databits = 8, stopbits = 1,parity = uart.None})

local function create_recv_handler(uart_id)
    log.info("创建接收回调函数","uart_id=",uart_id)
    return function(frame)
        if frame.fun == 0x01 then
            -- 处理读线圈响应（返回的是 bit 流）
            log.info("收到线圈响应", "数据长度:", #frame.payload)
            for i = 1, #frame.payload do
                local b = frame.payload:byte(i)
                log.info("第" .. (i - 1) * 8 .. "个线圈开始的字节:", string.format("%02X", b))
                for j = 0, 7 do
                    local coil_state = (b >> j) & 0x01 == 1
                    log.info("线圈", (i - 1)*8 + j, "=", coil_state)
                end
            end
        elseif frame.fun == 0x03 and #frame.payload >= 4 then -- 写保持寄存器
            log.info("串口:",uart_id,"寄存器1的数据为:",frame.payload:byte(1)*256+frame.payload:byte(2))
            log.info("串口:",uart_id,"寄存器2的数据为:",frame.payload:byte(3)*256+frame.payload:byte(4))
        elseif frame.fun == 0x05 and #frame.payload >= 4 then -- 写保持寄存器
            log.info("串口:",uart_id,"寄存器地址为:",frame.payload:byte(1)*256+frame.payload:byte(2),"写入的值为：",frame.value)
        elseif frame.fun == 0x06 and #frame.payload >= 4 then -- 写保持寄存器
            log.info("串口:",uart_id,"寄存器地址为:",frame.payload:byte(1)*256+frame.payload:byte(2),"写入的值为：",frame.value)
        elseif frame.fun == 0x0F and #frame.payload >= 4 then -- 写保持寄存器
            local start_addr = frame.payload:byte(1) * 256 + frame.payload:byte(2)
            local coil_count = frame.payload:byte(3) * 256 + frame.payload:byte(4)
            log.info("串口:", uart_id, "成功写入多个线圈", "起始地址:", start_addr, "数量:", coil_count)
        elseif frame.fun >= 0x80 then  -- 异常响应(功能码+0x80)
            local error_code = frame.payload:byte(1)
            log.error("串口", uart_id, "MODBUS异常", "功能码:0x"..string.format("%02X", frame.fun - 0x80),"错误码:"..error_code) 
        else
            log.warn("串口", uart_id, "未处理的功能码", "0x"..string.format("%02X", frame.fun),"长度:"..#frame.payload)
        end
    end
end

-- 设置主站接收回调
uart11:set_receive_callback(create_recv_handler(11))

-- 主站串口1循环发送读取保持寄存器的请求，间隔为3秒
sys.timerLoopStart(function()
    -- 主站11发送读取保持寄存器的请求功能码只有0x03所以无需设置  从站地址0x01，功能码0x03，起始地址0x0000，寄存器数量0x0002
    -- uart11:read_registers(0x01,0x00,0x02)

    -- 主站11发送写单个寄存器的请求 从站地址0x01，寄存器地址0x0000
    -- 功能码会根据数据类型自动判断 number是0x06 table是0x10
    -- local value = 3333
    -- uart11:write_registers(0x01,0x0000,value)

    -- 主站11发送写单个寄存器的请求 从站地址0x01，寄存器地址0x0000
    -- 功能码会根据数据类型自动判断 number是0x06 table是0x10
    -- local values = {111,222,333,444,555}
    -- uart11:write_registers(0x01,0x0000,values)

    -- 主站11发送读线圈的请求 从站地址253，寄存器地址0x0000
    -- uart11:read_coils(25,0x0000,5)

    -- 主站11发送写单个线圈的请求 从站地址25，寄存器地址0x0000
    -- uart11:write_coils(25,0,true)

    -- 主站11发送写多个线圈的请求 从站地址25，寄存器地址0x0000
    local values = {false,true,true,true,true,true,false}
    uart11:write_coils(25,0,values)
end,3000)

sys.run()
